﻿using LEE.AspNetCore.Extensions.Exceptions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Newtonsoft.Json;
using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace LEE.AspNetCore.Extensions.Middlewares
{
    /// <summary>
    /// 全局异常中间件
    /// </summary>
    public class GlobleExceptionMiddleware
    {
        private readonly RequestDelegate _next;

        protected GlobleExceptionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public virtual async Task Invoke(HttpContext context)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                var result = new ApiResult
                {
                    Success = false,
                    Code = 500
                };

                if (ex is CustomException customException)
                {
                    result.Code = customException.HttpStatusCode;
                    result.Message = customException.Message;
                }
                else
                {
                    result.Message = ex.GetBaseException().Message;
                    Log.Error(ex, $"{context.Request.Path}--Exception:{result.Message}");
                }
                await HandleExceptionAsync(context, result);
            }
            finally
            {
                stopwatch.Stop();
                Console.WriteLine("记录请求耗时：" + stopwatch.ElapsedMilliseconds);
            }
        }


        /// <summary>
        /// 重写已经响应结果
        /// </summary>
        /// <param name="context"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private static async Task HandleExceptionAsync(HttpContext context, ApiResult result)
        {
            var setting = new JsonSerializerSettings
            {
                ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
            };
            context.Response.StatusCode = 200;
            context.Response.ContentType = "application/json";
            await context.Response.WriteAsync(JsonConvert.SerializeObject(result, setting));
        }


        #region 读取Request参数

        private async Task<string> GetRequestParameters(HttpContext context)
        {
            //过滤文件上传请求
            if (context.Request.ContentType != null && context.Request.ContentType.Contains("multipart/form-data"))
            {
                return string.Empty;
            }
            var bodyString = await ReadBodyAsync(context.Request);
            if (string.IsNullOrEmpty(bodyString)) return string.Empty;
            bodyString = Regex.Replace(bodyString, "Password\":\"\\w+", "Password\":\"******", RegexOptions.IgnoreCase); //替换请求参数中的密码
            var bodyResult = JsonConvert.DeserializeObject<dynamic>(bodyString);
            var obj = new
            {
                QueryString = context.Request.Query,
                Body = bodyResult
            };
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// 读取请求body参数
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task<string> ReadBodyAsync(HttpRequest request)
        {
            if (request.ContentLength <= 0) return null;
            await EnableRewindAsync(request).ConfigureAwait(false);
            var encoding = GetRequestEncoding(request);
            return await this.ReadStreamAsync(request.Body, encoding).ConfigureAwait(false);
        }

        /// <summary>
        /// 获取请求参数类型和编码
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private static Encoding GetRequestEncoding(HttpRequest request)
        {
            var requestContentType = request.ContentType;
            var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType);
            var requestEncoding = requestMediaType.Encoding ?? Encoding.UTF8;
            return requestEncoding;
        }

        private static async Task EnableRewindAsync(HttpRequest request)
        {
            if (!request.Body.CanSeek)
            {
                request.EnableBuffering();
                await request.Body.DrainAsync(CancellationToken.None);
                request.Body.Seek(0L, SeekOrigin.Begin);
            }
        }

        private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding)
        {
            using (var sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放
            {
                var str = await sr.ReadToEndAsync();
                stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化，否则后面的InputFormatter会无法读取 
                return str;
            }
        }
        #endregion
    }



}
